package com.semidata.rtd.core.http.server;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.http.Cookie;
import io.netty.handler.codec.http.DefaultCookie;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.HttpVersion;
import io.netty.handler.codec.http.ServerCookieEncoder;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

public class HttpResponse {

    private ChannelHandlerContext ctx;
    private boolean keepAlive;
    private HttpResponseStatus status = HttpResponseStatus.OK;
    private ByteBuf buffer = Unpooled.buffer();

    private Map<String, Object> headers = new HashMap<>();
    private Set<Cookie> cookies = new HashSet<>();
    
    public HttpResponse(ChannelHandlerContext ctx, HttpRequest request) {

        this.keepAlive = HttpHeaders.isKeepAlive(request);
        this.ctx = ctx;

    }

    public void setStatus(HttpResponseStatus status) {
        this.status = status;
    }

    public <T> void appendBody(T body) {
        if (body instanceof ByteBuf)
            buffer.writeBytes((ByteBuf) body);
        else
            buffer.writeBytes(body.toString().getBytes());
    }

    public void setHeader(String key, Object value) {
        headers.put(key, value);
    }

    public void addCookie(String key, String value) {
        Cookie cookie = new DefaultCookie(key, value);
        cookie.setPath("/");
        cookie.setMaxAge(60 * 60 * 24 * 1000);
        cookies.add(cookie);
    }
    
    public void addCookie(Cookie cookie) {
        cookies.add(cookie);
    }

    public void end() {
        end("");
    }

    public <T> void end(T msg) {

        if (keepAlive) {
            setHeader(HttpHeaders.Names.CONNECTION, HttpHeaders.Values.KEEP_ALIVE);
        }

        appendBody(msg);

        if (!headers.containsKey(HttpHeaders.Names.CONTENT_TYPE)) {
            setHeader(HttpHeaders.Names.CONTENT_TYPE, "text/plain; charset=UTF-8");
        }
        setHeader(HttpHeaders.Names.CONTENT_LENGTH, buffer.writerIndex());

        FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, status, Unpooled.copiedBuffer(buffer));

        for (Map.Entry<String, Object> entry : headers.entrySet()) {
            response.headers().set(entry.getKey(), entry.getValue());
        }

        for (Cookie cookie : cookies) {
            response.headers().add(HttpHeaders.Names.SET_COOKIE, ServerCookieEncoder.encode(cookie));
        }
        ChannelFuture future = ctx.writeAndFlush(response);
        if (!keepAlive)
            future.addListener(ChannelFutureListener.CLOSE);
    }

    public void error() {
        error(HttpResponseStatus.BAD_REQUEST);
    }

    public void error(HttpResponseStatus status) {
        this.status = status;
        end();
    }

}
